const models = require("../models/index.js");
const User = models.User;
const uuid = require("uuid");
const mailService = require("./mail-service.js");
const tokenService = require("./token-service.js");
const UserDto = require("../dtos/user-dto.js");
const bcrypt = require("bcrypt");
const ApiError = require("../exceptions/api-error.js");

class UserService {
  // --------- Регистрация----------------------------------//--------------------------------------------

  async registration(email, password) {
    const candidate = await User.findOne({ where: { email } });
    if (candidate) {
      throw ApiError.badRequest(
        `Пользователь с почтой ${email} уже существует`
      );
    }
    const hashPassword = await bcrypt.hash(password, 5);
    const activationLink = uuid.v4();
    const user = await User.create({
      email,
      password: hashPassword,
      activationLink,
    });

    // ----------------Оправка письма на почту(активация)-------------------------------//--------------------------------------------

    await mailService.sendActivationMail(
      email,
      `${process.env.API_URL}/api/user/activate/${activationLink}`
    );

    const userDto = new UserDto(user);
    const tokens = tokenService.generateToken({ ...userDto });
    await tokenService.saveToken(userDto.id, tokens.refreshToken);

    return {
      ...tokens,
      user: userDto,
    };
  }

  // ------------------Активация-------------------------//--------------------------------------------

  async activate(activationLink) {
    const user = await User.findOne({ where: { activationLink } });
    if (!user) {
      throw ApiError.BadRequest("Некорректная ссылка активации");
    }
    user.isActivated = true;
    await user.save();
  }

  // ----------------Авторизация---------------------------//--------------------------------------------

  async login(email, password) {
    const user = await User.findOne({ where: { email } });
    if (!user) {
      throw ApiError.badRequest(`Пользователь с почтой ${email} не найден`);
    }
    const isPassEquals = await bcrypt.compare(password, user.password);
    if (!isPassEquals) {
      throw ApiError.badRequest("Неверный пароль");
    }
    const userDto = new UserDto(user);
    const tokens = tokenService.generateToken({ ...userDto });
    await tokenService.saveToken(userDto.id, tokens.refreshToken);
    return {
      ...tokens,
      user: userDto,
    };
  }

  // --------------------Выход из учетной записи---------------------------//--------------------------------------------

  async logout(refreshToken) {
    const token = await tokenService.removeToken(refreshToken);
    return token;
  }

  // ----------------------Перезапись токена-------------------------//--------------------------------------------

  async refresh(refreshToken) {
    if (!refreshToken) {
      throw ApiError.UnauthorizedError();
    }
    const userData = tokenService.validateRefreshToken(refreshToken);
    const tokenFromDb = await tokenService.findToken(refreshToken);
    if (!userData || !tokenFromDb) {
      throw ApiError.UnauthorizedError();
    }
    //findbyid does not support
    const user = await User.findOne({ where: { id: userData.id } });
    const userDto = new UserDto(user);
    const tokens = tokenService.generateToken({ ...userDto });
    await tokenService.saveToken(userDto.id, tokens.refreshToken);
    return {
      ...tokens,
      user: userDto,
    };
  }

  // -------------Все пользователи--------------------------------------//--------------------------------------------

  async getAllUsers() {
    const users = await User.findAll();
    return users;
  }

  // --------------Забыл пароль----------------------------------------//--------------------------------------------

  async reset_password(email) {
    const user = await User.findOne({ where: { email } });
    if (!user) {
      throw ApiError.badRequest(`Пользователь с почтой ${email} не найден`);
    }
    const recover_password_link = uuid.v4();
    user.RecoverPasswordLink = recover_password_link;
    await user.save();

    // ------------- Отправка письма на восстановлние пароля----------------------//----------------
    await mailService.sendResetPAsswordMail(
      email,
      `${process.env.API_URL}/api/user/reset/${activationLink}`
    );

    // const newPassword = uuid.v4();
    // const hashPassword = await bcrypt.hash(newPassword, 5);
    // user.password = hashPassword;
    // await user.save();
    // await mailService.sendResetPasswordMail(email, newPassword);
    // return newPassword;
  }

  // --------------Восстановление пароля---------------------------------//--------------------------------------------
  async recover_password(activationLink, newPassword) {
    const user = await User.findOne({ where: { activationLink } });
    if (!user) {
      throw ApiError.badRequest("Некорректная ссылка активации");
    }
    const hashPassword = await bcrypt.hash(newPassword, 5);
    user.password = hashPassword;
    await user.save();
  }
}

module.exports = new UserService();
